﻿using System;
using l1cs.server.utils;
using l1cs.server.model.Instance;
using System.Collections.Generic;
using System.Xml;
using System.Collections;

namespace l1cs.server.model.npc.action
{
    public abstract class L1NpcXmlAction : L1NpcAction
    {
        private String _name = null;
        private int[] _npcIds = null;
        private IntRange _level = null;
        private int _questId = -1;
        private int _questStep = -1;
        private int[] _classes = null;

        public L1NpcXmlAction() { }

        public L1NpcXmlAction( XmlReader reader )
        {
            Hashtable attribute = L1NpcXmlParser.getAllAttribute( reader );
            _name = (string)attribute["Name"];
            _npcIds = parseNpcIds( (string)attribute["NpcId"] );
            _level = parseLevel( attribute );
            _questId = L1NpcXmlParser.parseQuestId( (string)attribute["QuestId"] );
            _questStep = L1NpcXmlParser.parseQuestStep( (string)attribute["QuestStep"] );

            _classes = parseClasses( attribute );
        }

        public void setData( Hashtable attribute )
        {
            _name = (string)attribute["name"];
            _name = _name.Equals( "" ) ? null : _name;
            _npcIds = parseNpcIds( (string)attribute["npcid"] );
            _level = parseLevel( attribute );
            _questId = L1NpcXmlParser.parseQuestId( (string)attribute["QuestId"] );
            _questStep = L1NpcXmlParser.parseQuestStep( (string)attribute["QuestStep"] );

            _classes = parseClasses( attribute );
        }

        public void addAction( L1NpcAction action ) { }

        private int[] parseClasses( Hashtable attribute )
        {
            String classes = (string)attribute["Class"];
            if ( classes == null )
            {
                return new int[0];
            }
            classes = classes.ToUpper();
            int[] result = new int[classes.Length];
            int idx = 0;
            foreach ( char cha in classes.ToCharArray() )
            {
                result[idx++] = _charTypes[cha];
            }
            Array.Sort( result );
            return result;
        }

        private IntRange parseLevel( Hashtable attribute )
        {
            int level = L1NpcXmlParser.getIntAttribute( (string)attribute["level"], 0 );
            int min = L1NpcXmlParser.getIntAttribute( (string)attribute["levelmin"], 1 );
            int max = L1NpcXmlParser.getIntAttribute( (string)attribute["levelmax"], 99 );
            return level == 0 ? new IntRange( min, max ) : new IntRange( level, level );
        }

        private static Dictionary<char, int> _charTypes = new Dictionary<char, int>();
        static L1NpcXmlAction()
        {
            _charTypes.Add( 'P', 0 );
            _charTypes.Add( 'K', 1 );
            _charTypes.Add( 'E', 2 );
            _charTypes.Add( 'W', 3 );
            _charTypes.Add( 'D', 4 );
            _charTypes.Add( 'R', 5 );
            _charTypes.Add( 'I', 6 );
        }

        private int[] parseNpcIds( String npcIds )
        {
            if ( npcIds == null )
            {
                return new int[0];
            }
            StringTokenizer tok = new StringTokenizer( npcIds.Replace( " ", "" ), "," );
            int[] result = new int[tok.countTokens()];
            for ( int i = 0; i < result.Length; i++ )
            {
                result[i] = Convert.ToInt32( tok.nextToken() );
            }
            Array.Sort( result );
            return result;
        }

        private bool acceptsNpcId( L1Object obj )
        {
            if ( 0 < _npcIds.Length )
            {
                if ( !( obj is L1NpcInstance ) )
                {
                    return false;
                }
                int npcId = ( (L1NpcInstance)obj ).getNpcTemplate().get_npcId();

                if ( Array.BinarySearch( _npcIds, npcId ) < 0 )
                {
                    return false;
                }
            }
            return true;
        }

        private bool acceptsLevel( int level )
        {
            return _level.includes( level );
        }

        private bool acceptsCharType( int type )
        {
            if ( 0 < _classes.Length )
            {
                if ( Array.BinarySearch( _classes, type ) < 0 )
                {
                    return false;
                }
            }
            return true;
        }

        private bool acceptsActionName( String name )
        {
            if ( _name == null )
            {
                return true;
            }
            return name.Equals( _name );
        }

        private bool acceptsQuest( L1PcInstance pc )
        {
            if ( _questId == -1 )
            {
                return true;
            }
            if ( _questStep == -1 )
            {
                return 0 < pc.getQuest().get_step( _questId );
            }
            return pc.getQuest().get_step( _questId ) == _questStep;
        }

        public bool acceptsRequest( String actionName, L1PcInstance pc, L1Object obj )
        {
            if ( !acceptsNpcId( obj ) )
            {
                return false;
            }
            if ( !acceptsLevel( pc.getLevel() ) )
            {
                return false;
            }
            if ( !acceptsQuest( pc ) )
            {
                return false;
            }
            if ( !acceptsCharType( pc.getType() ) )
            {
                return false;
            }
            if ( !acceptsActionName( actionName ) )
            {
                return false;
            }
            return true;
        }

        public abstract L1NpcHtml execute( String actionName, L1PcInstance pc, L1Object obj, byte[] args );

        public L1NpcHtml executeWithAmount( String actionName, L1PcInstance pc, L1Object obj, int amount )
        {
            return null;
        }
    }
}